package pl.edu.mimuw.irs.rcp.controller.editor.simulation.part;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.draw2d.Label;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.RootEditPart;

import pl.edu.mimuw.irs.core.model.analysis.resources.Fire;
import pl.edu.mimuw.irs.core.model.analysis.resources.Hire;
import pl.edu.mimuw.irs.core.model.design.net.IRSNode;
import pl.edu.mimuw.irs.core.model.petrinet.Transition;
import pl.edu.mimuw.irs.core.model.simulation.atomic.EventTransition;
import pl.edu.mimuw.irs.rcp.controller.editor.workflow.part.ArcEditPart;
import pl.edu.mimuw.irs.rcp.controller.editor.workflow.part.IRSNodeEditPart;
import pl.edu.mimuw.irs.rcp.controller.editor.workflow.part.PlaceEditPart;
import pl.edu.mimuw.irs.rcp.controller.editor.workflow.part.TransitionEditPart;
import pl.edu.mimuw.irs.rcp.view.figure.FigureWrapper;
import pl.edu.mimuw.irs.rcp.view.figure.SimulationTransitionShape;


/**
 * @author Jakub Rauch
 * Created on: 2009-05-28
 */
public class SimulationTransitionEditPart extends TransitionEditPart implements
		SimulationEditPart, PropertyChangeListener {

	// *** Attributes

	// *** Methods

	@Override
	public void activate() {
		getTransition().addPropertyChangeListener(EventTransition.ACTIVE, this);
		getTransition().addPropertyChangeListener(EventTransition.ACTIVEALLOWED, this);
		getTransition().addPropertyChangeListener(EventTransition.CALCULATIONS, this);
		super.activate();
	}
	
	@Override
	public void deactivate() {
		getTransition().removePropertyChangeListener(EventTransition.ACTIVE, this);
		getTransition().removePropertyChangeListener(EventTransition.ACTIVEALLOWED, this);
		getTransition().removePropertyChangeListener(EventTransition.CALCULATIONS, this);
		super.deactivate();
	}
	
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		refresh();
	}
	
	protected NodeShape getNodeShape() {
		return NodeShape.TGTRANSITION;
	}
	
	@Override
	protected void refreshVisuals() {
		Transition transition = (Transition)getNode();
		FigureWrapper wrapper = (FigureWrapper)getFigure();
		SimulationTransitionShape shape = (SimulationTransitionShape) wrapper.getFigure();
		
		if (transition instanceof EventTransition) {
			EventTransition eventTransition = (EventTransition) transition;
			shape.setActive(eventTransition.isActive() && eventTransition.isActiveAllowed());
			if (shape.isActive() && eventTransition.getCalculations().getRuns().size() > 0) 
				shape.setToolTip(new Label(eventTransition.getCalculations().toString()));
		} else {
			shape.setActive(transition.isActive());
			shape.setToolTip(null);
		}
		
		
		super.refreshVisuals();
	}
	
	public void performRequest(Request req) {
		if (req.getType().equals(RequestConstants.REQ_OPEN)){
			Transition transition = (Transition)getNode();
			if (transition instanceof EventTransition) {
				EventTransition eventTransition = (EventTransition) transition;
				if (eventTransition.isActive() && eventTransition.isActiveAllowed()) transition.invoke();
			} else {
				if (transition.isActive()) transition.invoke();
			}
			
			if (transition instanceof Hire || transition instanceof Fire) {
				refresh(getRoot());
			} else {
				refreshTokens();
				refreshTransitions();
			}
		}
		super.performRequest(req);
	}

	public void refreshTokens() {
		for (Object editPart : getSourceConnections()) {
			ArcEditPart arcEditPart = (ArcEditPart) editPart;
			arcEditPart.getTarget().refresh();
		}
		for (Object editPart : getTargetConnections()) {
			ArcEditPart arcEditPart = (ArcEditPart) editPart;
			arcEditPart.getSource().refresh();
		}
	}
	
	private void refreshTransitions() {
		Set<TransitionEditPart> transitions = new LinkedHashSet<TransitionEditPart>();
		for (Object editPart : getSourceConnections()) {
			ArcEditPart arcEditPart = (ArcEditPart) editPart;
			PlaceEditPart placeEditPart = (PlaceEditPart) arcEditPart.getTarget();
			// These transitions can be activated
			for (Object editPart2 : placeEditPart.getSourceConnections()) {
				ArcEditPart arcEditPart2 = (ArcEditPart) editPart2;
				TransitionEditPart transitionEditPart = (TransitionEditPart) arcEditPart2.getTarget();
				if (!transitions.contains(transitionEditPart)) transitions.add(transitionEditPart);
			}
		}
		for (Object editPart : getTargetConnections()) {
			ArcEditPart arcEditPart = (ArcEditPart) editPart;
			PlaceEditPart placeEditPart = (PlaceEditPart) arcEditPart.getSource();
			// Some of these transitions can be deactivated
			for (Object editPart2 : placeEditPart.getSourceConnections()) {
				ArcEditPart arcEditPart2 = (ArcEditPart) editPart2;
				TransitionEditPart transitionEditPart = (TransitionEditPart) arcEditPart2.getTarget();
				if (!transitions.contains(transitionEditPart)) transitions.add(transitionEditPart);
			}
		}
		for (TransitionEditPart editPart : transitions) {
			editPart.refresh();
		}
	}
	
	@SuppressWarnings("unchecked")
	private void refresh(EditPart editPart) {
		editPart.refresh();
		List<EditPart> children = editPart.getChildren();
		if (editPart instanceof RootEditPart) {
			for (EditPart childEditPart : children) {
				refresh(childEditPart);
			}
		} else if (editPart instanceof IRSNodeEditPart) {
			IRSNodeEditPart nodeEditPart = (IRSNodeEditPart)editPart;
			IRSNode node = nodeEditPart.getIRSNode();
			if (node.isExpanded()) {
				for (EditPart childEditPart : children) {
					refresh(childEditPart);
				}
			}
		} else {
			for (EditPart childEditPart : children) {
				childEditPart.refresh();
			}
		}
	}
}
